`timescale	1ps/1ps
module v8_com_ctrl_01(
		input	wire		resetb,
		input	wire		sclk,
		input	wire		comm_en,
		input	wire		sub_mode,

		//网口配置总线
	        input	wire		set_d_ok,
	        input	wire	[15:0]	set_addr,
	        input	wire	[7:0]	set_data,
	        
		output	wire	[1:0]	depth_state,
		output	reg	[9:0]	current_depth,
		
		input	wire		rec_flag,
		input	wire		rec_error,
		input	wire	[7:0]	rec_data,
		input	wire	[1:0]	rec_vendor, //0:无效包 1：中庆UDP 2：YT 3：中庆长包
		
		output	reg		send_flag,
		output	reg		pre_flag,
		output	wire	[7:0]	send_data,
		
		input	wire		blank_flag,
		input	wire		redu_flag,
		input	wire		time_1ms_sync,
				
		output	reg		op_addr_mcu,

		output	wire		fpga_rec_flag,
		output	wire		fpga_send_flag,	
		output	reg		op_start_flag,
		output	reg	[31:0]	op_start_addr,
		output	wire	[7:0]	op_length,
		input	wire		op_ack,

		input	wire		fpga_rec_end,
		input	wire	[7:0]	rec_buf_raddr,
		output	wire	[7:0]	rec_buf_rdata,

		input	wire		fpga_send_end,
		input	wire		send_buf_we,
		input	wire	[7:0]	send_buf_waddr,
		input	wire	[7:0]	send_buf_wdata,

		output	wire	[7:0]	tout
		);

//************************************************/
//		参数定义
//************************************************/
//************************************************/
parameter  Preamble_OFFSET	= 23;
parameter  PACK_TYPE_FIRST	= 24 - 1;
parameter  ASI_DEPTH_FIRST	= 26 - 1;
parameter  PACK_DEPTH_FIRST	= 28 - 1;
parameter  COM_PACK_SEL_TYPE	= 30 - 1;
parameter  COM_PACK_SEL_ADDR	= 31 - 1;
parameter  COM_PACK_ASI_ADDR	= 33 - 1;
parameter  COM_PACK_COMMAND	= 38 - 1;
parameter  COM_PACK_ADDR	= 40 - 1;
parameter  COM_PACK_HEAD_END	= 43 - 1;

parameter  TIMEOUT	        = 10;

//*************state******************************
parameter  IDLE_STATE		= 6'h01;
parameter  WAIT_STATE		= 6'h02;
parameter  COM_RECEIVE		= 6'h04;
parameter  FPGA_RECEIVE		= 6'h08;
parameter  FPGA_SEND		= 6'h10;
parameter  SEND_FEEDBACK	= 6'h20;

///**************命令类型****************
parameter  MEM_READ		= 8'h08;
parameter  MEM_WRITE		= 8'h04;

//**********************************************/
//		信号定义
/************************************************/
reg		buf_wen;
reg	[10:0]	buf_addr;
reg	[7:0]	buf_wdata;
wire	[7:0]	buf_rdata;

reg	[5:0]	com_state;
reg	[8:0]	data_count;
reg		head_flag,head_end,com_packet_flag;
reg	[7:0]	current_depth_c;
reg		device_active,read_command,write_command,data_end;
reg	[23:0]	op_page_addr;
reg		com_rec_temp,send_flag_a,send_flag_b;
reg		rec_data_wen;

reg             buf_wen_a,buf_wen_b;
reg     [9:0]	buf_addr_a;
wire    [9:0]	buf_addr_b;
reg	[1:0]	ack_head_type_t1,ack_head_type;
reg		udp_head,udp_head_end;

reg		fpga_send_end_flag;
reg		send_timeout;
reg	[3:0] 	ms_count;

reg	[3:0]	op_ack_count;
reg		no_ack;

reg	[2:0]	rec_flag_t;
reg		local_depth_en, cas_depth_adj;
reg	[7:0]	local_depth;
reg		local_depth_en_t;
reg	[9:0]	cas_depth, t_depth;

reg		op_addr_mask;
reg		device_active_a;
//*************************************************/
//		通讯buf
//*************************************************/	
//swsr_2k8_dp com_buf(
//	.clka(sclk),
//	.wea(buf_wen),
//	.addra(buf_addr),
//	.dina(buf_wdata),
//	
//	.clkb(sclk),
//	.addrb(buf_addr),
//	.doutb(buf_rdata)
//	);
	
/*swsr_2k8_tp_com_mif com_buf(
	.clka(sclk),
	.wea(buf_wen_a),
	.addra(buf_addr_a),
	.dina(send_buf_wdata),
	.douta(buf_rdata),
	
	.clkb(sclk),
	.web(buf_wen_b),
	.addrb(buf_addr_b),
	.dinb(rec_data),
	.doutb());*/
	
//com_buf 140516修改 UDP时desport为5AA5
v8_swsr_1k8_tp_com_mif	com_buf (
	.clock_a ( sclk ),
	.wren_a ( buf_wen_a ),
	.address_a ( buf_addr_a ),
	.data_a ( send_buf_wdata ),
	.q_a ( buf_rdata ),
	
	.clock_b ( sclk ),
	.address_b ( buf_addr_b ),
	.wren_b ( buf_wen_b ),
	.data_b ( rec_data ),
	.q_b ()
	);

/************************************************/
//		设备类型设置
/************************************************/
reg	[2:0]	BIT_ALL;
reg	[5:0]	C_FIRST, T_FIRST;
reg	[13:0]	INITIAL_ADDR, TEST_ADDR, ACTIVE_ADDR; 
wire	[13:0]	INITIAL_ERASE_ADDR, TEST_ERASE_ADDR, ACTIVE_ERASE_ADDR;

//设备类型
always @( * )
	if (sub_mode == 1) begin
		BIT_ALL <= 0;
		C_FIRST <= PACK_DEPTH_FIRST;
		T_FIRST <= COM_PACK_SEL_ADDR;
		end
	else begin
		BIT_ALL <= 2;
		C_FIRST <= ASI_DEPTH_FIRST;
		T_FIRST <= COM_PACK_ASI_ADDR;
		end

//Flash地址
always @( * )
	if (sub_mode == 1) begin
		INITIAL_ADDR	<=14'b0000_0000_1010_00;
		TEST_ADDR	<=14'b0000_0000_1010_01;
		ACTIVE_ADDR	<=14'b0000_0000_1010_10;
		end
	else begin
		INITIAL_ADDR	<=14'b0000_0000_1110_00;
		TEST_ADDR	<=14'b0000_0000_1110_01;
		ACTIVE_ADDR	<=14'b0000_0000_1110_10;
		end

assign INITIAL_ERASE_ADDR	=INITIAL_ADDR + 4;
assign TEST_ERASE_ADDR		=TEST_ADDR + 4;
assign ACTIVE_ERASE_ADDR	=ACTIVE_ADDR + 4;
/************************************************/
//		参数设置
/************************************************/
always	@(posedge sclk or negedge resetb)
	if (resetb==0)
		begin
			local_depth	<= 0;
			local_depth_en_t<= 0;
			cas_depth_adj	<= 0;
		end
	else if (set_d_ok==1)
		case (set_addr)
			16'h0209:	local_depth <= set_data;  
			16'h020a:	begin
			                if(set_data == 8'h3C)                 //与未加多屏功能的配置文件保持兼容
			                        local_depth_en_t <= 1; 	
			                else 
			                	local_depth_en_t <= 0;
			                end		     
			16'h020b:	begin
			                if(set_data == 8'h3C)                 //与未加多屏功能的配置文件保持兼容
			                        cas_depth_adj <= 1; 	
			                else 
			                	cas_depth_adj <= 0;
			                end		     
		endcase

always	@(posedge sclk)
	if (cas_depth_adj == 1)
		local_depth_en <= 1;
	else
		local_depth_en <= local_depth_en_t;

assign	depth_state={cas_depth_adj, local_depth_en};

//************************************************/
//		状态控制
//************************************************/
//**************主状态机*******************
always@(posedge sclk or negedge resetb)
	if(resetb == 0)
		com_state <= IDLE_STATE;
	else 
		case(com_state)
			IDLE_STATE:	
				if (comm_en==0)
					com_state <= WAIT_STATE;	
				else if (rec_flag==1)
					com_state <= COM_RECEIVE;	

			WAIT_STATE:
				if(rec_flag==0 && comm_en==1)
					com_state <= IDLE_STATE;

			COM_RECEIVE:
				if ((rec_flag == 0) && (rec_flag_t[1] == 0)) begin
					if ((rec_error == 1) || (com_packet_flag == 0) || (device_active == 0) || (op_addr_mask == 1))
						com_state <= IDLE_STATE;
					else if (write_command == 1)
						com_state <= FPGA_RECEIVE;
					else if (read_command == 1)
						com_state <= FPGA_SEND;
					else
						com_state <= IDLE_STATE;
					end
					
			FPGA_RECEIVE:
				if(fpga_rec_end == 1 || no_ack == 1)
					com_state <= WAIT_STATE;
							
			FPGA_SEND:
				if(fpga_send_end_flag==1 || no_ack == 1)
				begin
					if(redu_flag==0)	//单向级联模式
						com_state <= SEND_FEEDBACK;
					else if(blank_flag==1 || send_timeout==1)	//双口冗余模式，等空闲包
						com_state <= SEND_FEEDBACK;
				end
			SEND_FEEDBACK:
				if(data_end == 1)
					com_state <= WAIT_STATE;
							
			default:	com_state <= WAIT_STATE;
		endcase

//**************rec_flag缓冲*******************
always	@(posedge sclk)
	rec_flag_t <= {rec_flag_t[1:0], rec_flag};

//**************通讯包有效数据计数*******************
//包头标志
always	@(posedge sclk)
	if (com_state==IDLE_STATE || com_state==FPGA_SEND)
		head_flag<=1;
	else if (head_end==1)
		head_flag<=0;

//包头结束标志
always	@(posedge sclk)
	if (head_flag==1 && data_count==COM_PACK_HEAD_END-1 && udp_head==0)
		head_end<=1;
	else
		head_end<=0;

//数据计数
//always	@(posedge sclk)
//	if (com_state==IDLE_STATE)
//		data_count<=23;
//	else if (head_end==1 || com_state==FPGA_SEND)
//		data_count<=0;
//	else if (com_state==COM_RECEIVE || com_state==SEND_FEEDBACK)
//		data_count<=data_count+1;
		
always	@(posedge sclk)
	if (com_state==IDLE_STATE || udp_head_end==1)
		data_count<=23;
	else if (head_end==1 )//|| com_state==FPGA_SEND)
		data_count<=0;
	else if(com_state==FPGA_SEND) begin
		if(redu_flag==1)
			data_count<=20;	//去掉部分包头，用于冗余替换空闲包数据
		else
			data_count<=0;
		end
	else if (com_state==COM_RECEIVE || com_state==SEND_FEEDBACK)
		data_count<=data_count+1;

always	@(posedge sclk or negedge resetb)
	if(resetb==0)
		udp_head<=0;
	else if(com_state==FPGA_SEND && ack_head_type==1) 
		udp_head<=1;
	else if(udp_head_end==1)
		udp_head<=0;

always	@(posedge sclk or negedge resetb)
	if(resetb==0)
		udp_head_end<=0;
	else if(com_state==SEND_FEEDBACK && udp_head==1 && data_count==49)
		udp_head_end<=1;
	else
		udp_head_end<=0;
//**************通讯包解码*******************
always	@(posedge sclk)
	if (com_state!=COM_RECEIVE)
		com_packet_flag<=0;
	else if (head_flag==1 && data_count[5:0]==PACK_TYPE_FIRST && rec_data==8'hC5 && (rec_vendor==1 || rec_vendor==3))
		com_packet_flag<=1;

//从数据包中提取级联深度数据
always	@(negedge resetb or posedge sclk)
	if (resetb == 0)
		cas_depth <= 1;
	else if ((com_state == COM_RECEIVE) && (head_flag == 1)) begin
		if  (data_count[5:0] == C_FIRST)
			cas_depth[7:0] <= rec_data;
		else if (data_count[5:0] == C_FIRST + 1)
			cas_depth[9:8] <= rec_data;
		end
		
//从数据包中提取目标深度数据
always	@(negedge resetb or posedge sclk)
	if (resetb == 0)
		t_depth <= 1;
	else if ((com_state == COM_RECEIVE) && (head_flag == 1)) begin
		if  (data_count[5:0] == T_FIRST)
			t_depth[7:0] <= rec_data;
		else if (data_count[5:0] == T_FIRST + 1)
			t_depth[9:8] <= rec_data;
		end
		
//确定级联深度
always	@(posedge sclk or negedge resetb)
	if(resetb == 0)
		current_depth <= 1;
	else if (local_depth_en == 1)
		current_depth <= local_depth;
	else if ((rec_flag == 0) && (rec_flag_t[0] == 1) && (rec_error == 0))
		current_depth <= cas_depth;

//设备选择识别
always	@(posedge sclk)
	if (com_state != COM_RECEIVE)
		device_active_a <= 0;
	else if (head_flag == 1 && data_count[5:0] == COM_PACK_SEL_TYPE && rec_data[BIT_ALL] == 1)
		device_active_a <= 1;
	else if ((data_count[5:0] == T_FIRST + 2) && (current_depth == t_depth))
		device_active_a <= 1;

always	@(posedge sclk)
	if (com_state != COM_RECEIVE)
		device_active <= 0;
	else if ((rec_flag_t[0] == 0) && (rec_flag_t[1] == 1))
		device_active <= device_active_a;
	
//设备选择识别
always	@( * )
	if ((device_active_a == 1)&& (op_addr_mask == 1))
		op_addr_mcu <= 1;
	else
		op_addr_mcu <= 0;
	
always	@(posedge sclk)
	if (com_state!=COM_RECEIVE)
		read_command<=0;
	else if (head_flag==1 && data_count[5:0]==COM_PACK_COMMAND)
		read_command<=rec_data[3];

always	@(posedge sclk)
	if (com_state!=COM_RECEIVE)
		write_command<=0;
	else if (head_flag==1 && data_count[5:0]==COM_PACK_COMMAND)
		write_command<=rec_data[2];

always	@(posedge sclk or negedge resetb)
	if (resetb==0)
		op_page_addr<=0;
	else if (com_state==COM_RECEIVE && head_flag==1 && com_packet_flag==1)
		case(data_count)
			COM_PACK_ADDR+1 :  op_page_addr[7:0]	<=rec_data;
			COM_PACK_ADDR+2 :  op_page_addr[15:8]	<=rec_data;
			COM_PACK_ADDR+3 :  op_page_addr[23:16]	<=rec_data;
		endcase

/***************应答包长度控制**********************/
always	@(posedge sclk)
	if (data_count==255-1)
		data_end<=1;
	else
		data_end<=0;

reg	com_packet_t;
reg	[5:0]	com_state_t;
always	@(posedge sclk)
	begin
		com_packet_t<=com_packet_flag;
		com_state_t<=com_state;
	end
	
always	@(posedge sclk or negedge resetb)
	if(resetb==0)
		ack_head_type_t1<=0;
	else if (com_packet_t==0 && com_packet_flag==1)
		ack_head_type_t1<=rec_vendor;

always	@(posedge sclk or negedge resetb)
	if(resetb==0)
		ack_head_type<=0;
	else if(com_state_t==COM_RECEIVE && com_state==FPGA_SEND)
		ack_head_type<=ack_head_type_t1;

//**********************************************************************/
//		给内部接口模块信号
//**********************************************************************/	
assign	op_length	=255;
//assign	op_start_addr	={op_page_addr,8'h0};

always	@(posedge sclk or negedge resetb)
	if(resetb==0)
		op_start_addr<=0;
	else 
	case(op_page_addr[23:10])
		INITIAL_ADDR:		op_start_addr<={12'h004,2'h0,op_page_addr[9:0],8'h0};
		TEST_ADDR:		op_start_addr<={12'h004,2'h1,op_page_addr[9:0],8'h0};
		ACTIVE_ADDR:		op_start_addr<={12'h004,2'h2,op_page_addr[9:0],8'h0};
		
		INITIAL_ERASE_ADDR:	op_start_addr<={12'h005,2'h0,op_page_addr[9:0],8'h0};
		TEST_ERASE_ADDR:	op_start_addr<={12'h005,2'h1,op_page_addr[9:0],8'h0};
		ACTIVE_ERASE_ADDR:	op_start_addr<={12'h005,2'h2,op_page_addr[9:0],8'h0};
		
		{12'h004,2'h0}:		op_start_addr<={12'h800,op_page_addr[11:0],8'h0};      	//操作地址为0x0040_0000~0x0043_FFFF时(被重定义）  
		{12'h004,2'h1}:		op_start_addr<={12'h800,op_page_addr[11:0],8'h0};      	//操作地址为0x0044_0000~0x0047_FFFF时(被重定义）  
		{12'h004,2'h2}:		op_start_addr<={12'h800,op_page_addr[11:0],8'h0};      	//操作地址为0x0048_0000~0x004B_FFFF时(被重定义）  
		                	                                                       	//映射修改到0x8000_0000~0x800B_FFFF地址（无用地址） 
		{12'h005,2'h0}:		op_start_addr<={12'h800,op_page_addr[11:0],8'h0};      	//操作地址为0x0050_0000~0x0053_FFFF时(被重定义）  
		{12'h005,2'h1}:		op_start_addr<={12'h800,op_page_addr[11:0],8'h0};      	//操作地址为0x0054_0000~0x0057_FFFF时(被重定义）  
		{12'h005,2'h2}:		op_start_addr<={12'h800,op_page_addr[11:0],8'h0};      	//操作地址为0x0058_0000~0x005B_FFFF时(被重定义）  
		                                                                               	//映射修改到0x8000_0000~0x800B_FFFF地址（无用地址） 
		default:		op_start_addr<={op_page_addr,8'h0}; 			//其他为原地址
	endcase
                   
always	@(posedge sclk or negedge resetb)
	if(resetb==0)
		op_addr_mask <= 0;
	else if (op_page_addr[23:20] == 4'h2)		//0x2XXX_XXXX
		op_addr_mask <= 1;
	else if (op_page_addr[23:20] == 4'h1)		//0x1XXX_XXXX
		op_addr_mask <= 1;
	else if (op_page_addr[23:4] == 20'h00002)	//0x0000_2XXX
		op_addr_mask <= 1;
	else
		op_addr_mask <= 0;
                   
assign	fpga_rec_flag	=com_state[3];
assign	fpga_send_flag	=com_state[4];

always	@(posedge sclk)
	com_rec_temp<=com_state[2];

always	@(posedge sclk)
	if ((fpga_rec_flag==1 || fpga_send_flag==1) && com_rec_temp==1 && op_addr_mask == 0)
		op_start_flag<=1;
	else
		op_start_flag<=0;

//**********************************************************************/
//		响应检测
//**********************************************************************/
//ack检测延时
always	@(posedge sclk or negedge resetb)
	if (resetb==0)
		op_ack_count <= 0;
	else if (op_start_flag == 1)
		op_ack_count <= 0;
	else if (op_ack_count[3] == 1'b0)
		op_ack_count <= op_ack_count + 1;
	
//无模块响应标志
always	@(posedge sclk or negedge resetb)
	if (resetb==0)
		no_ack <= 0;
	else if (com_rec_temp == 1)			//通讯接收态，清除无反馈标志
		no_ack <= 0;
	else if (op_ack_count == 6 && op_ack == 0)	//根据外部响应设置无反馈标志
		no_ack <= 1;

//**********************************************************************/
//		应答包发送
//**********************************************************************/
always	@(posedge sclk or negedge resetb)
	if (resetb==0)
		send_flag<= 0;
	else if (com_state==SEND_FEEDBACK)
		send_flag<= 1;
	else
		send_flag<=0;
	
always	@*
	if (com_state==SEND_FEEDBACK && head_flag==1 && data_count>=1 && data_count<=8)
		pre_flag<= 1;
	else
		pre_flag<= 0;

assign	send_data=buf_rdata;

//**********************************************************************/
//		内部BUF控制
//**********************************************************************/	
//*****************写控制*****************
always	@(posedge sclk)
	if (com_state!=COM_RECEIVE)
		rec_data_wen<= 0;
	else if (data_count==COM_PACK_SEL_TYPE-1)
		rec_data_wen<= 1;
	else if (data_end==1)
		rec_data_wen<= 0;
				
always	@*	
        if(com_state==FPGA_SEND && send_buf_we==1)
                buf_wen_a<=1;
        else
                buf_wen_a<=0;
        
always	@*
        buf_wen_b<=rec_data_wen;

always	@*
	if (com_state==FPGA_RECEIVE)
		buf_addr_a<= {2'b00,rec_buf_raddr}; 
        else if(com_state==FPGA_SEND)
		buf_addr_a<={2'b01,send_buf_waddr};	
	else if(udp_head==1)
		buf_addr_a<={2'b10,1'b1,data_count[6:0]};
	else if(head_flag==1)
		buf_addr_a<={2'b10,data_count[7:0]};
	else if(com_state==SEND_FEEDBACK)
	        buf_addr_a<={2'b01,data_count[7:0]};
	else
		buf_addr_a<=0;

assign  buf_addr_b={head_flag,1'b0,data_count[7:0]};
						
assign	rec_buf_rdata=buf_rdata;

/************************************************/
//		超时反馈控制
/************************************************/
always	@(posedge sclk)
	if(com_state!=FPGA_SEND)
		fpga_send_end_flag<=0;
	else if(fpga_send_end==1)
		fpga_send_end_flag<=1;

always	@(posedge sclk or negedge resetb)
	if(resetb==0)
		ms_count<=0;
	else if(time_1ms_sync==1)begin
		if(fpga_send_end_flag==0)
			ms_count<=0;
		else if(ms_count==TIMEOUT-1)
			ms_count<=0;
		else
			ms_count<=ms_count+1;
		end
		
always	@(posedge sclk)
	if(time_1ms_sync==1 && ms_count==TIMEOUT-1)
		send_timeout<=1;
	else
		send_timeout<=0;
/************************************************/
//		测试信号
/************************************************/
assign	tout = {com_state, device_active, com_packet_flag};

endmodule		

